﻿using System;
using System.Collections.Generic;
using System.Windows.Media.Imaging;
using Gamelight.Graphics;
using Gamelight.Sound;

namespace Gamelight.Data
{
	public static class Resources
	{
		private static Dictionary<string, Image> originalImages = new Dictionary<string, Image>();
		private static Dictionary<string, GamelightMediaStream> mediaStreams = new Dictionary<string, GamelightMediaStream>();
		private static Dictionary<string, string[]> assemblyNameToFileList = new Dictionary<string, string[]>();

		public static void RegisterResourceAssembly(System.Reflection.Assembly assembly)
		{
			AssemblyStreamManager.RegisterAssembly(assembly);
		}

		internal static void RegisterFileNamesFromAssembly(System.Reflection.Assembly assembly)
		{
			string[] files = assembly.GetManifestResourceNames();
			string assemblyName = AssemblyStreamManager.GetAssemblyShortName(assembly);

			// TODO: check to see if this array reference is identical between calls. If so,
			// the array must be copied to protect its integrity from accidental editing. 
			List<string> filenames = new List<string>(assembly.GetManifestResourceNames());
			assemblyNameToFileList[assemblyName] = filenames.ToArray();
		}

		public static void RegisterResourceAssembly(Type typeInAssembly)
		{
			AssemblyStreamManager.RegisterAssembly(typeInAssembly.Assembly);
		}

		public static void SetDefaultResourceAssembly(string assemblyName)
		{
			AssemblyStreamManager.SetDefaultAssembly(assemblyName);
		}

		public static string[] GetResourcePathsFromAssembly(string assemblyName)
		{
			// If the key does not exist, they're asking for trouble anyway. 

			string[] output;
			if (assemblyNameToFileList.TryGetValue(assemblyName, out output))
			{
				return output;
			}

			throw new Gamelight.InvalidOperationException("An assembly must be registered first before it can be referenced by name.");
		}

		internal static Image GetImageCopy(string assembly, string path)
		{
			string key = AssemblyStreamManager.CanonicalizeEmbeddedResourceName(assembly, path);

			Image original;
			if (!originalImages.TryGetValue(key, out original))
			{
				original = LoadImageFresh(assembly, path);
				originalImages[key] = original;
			}

			return new Image(original);
		}

		private static Image LoadImageFresh(string assembly, string path)
		{
			System.IO.Stream stream = AssemblyStreamManager.GetFreshStream(assembly, path);
			return LoadImageFresh(stream);
		}

		private static Image LoadImageFresh(System.IO.Stream stream)
		{
			BitmapImage bmp = new BitmapImage();
			bmp.SetSource(stream);
			WriteableBitmap wBmp = new WriteableBitmap(bmp);
			Image img = new Image(wBmp);

			return img;
		}

		internal static GamelightMediaStream GetMediaStream(string assembly, string path)
		{
			string key = AssemblyStreamManager.CanonicalizeEmbeddedResourceName(assembly, path);

			GamelightMediaStream mediaStream;
			if (!mediaStreams.TryGetValue(key, out mediaStream))
			{
				mediaStream = new GamelightMediaStream(assembly, path);
			}

			return mediaStream;
		}

		public static void PreloadAllImages(string assemblyName)
		{
			Dictionary<string, System.IO.Stream> streams = AssemblyStreamManager.GetAllStreams(assemblyName, AssemblyStreamManager.MediaType.Image);
			foreach (string key in streams.Keys)
			{
				originalImages[key] = LoadImageFresh(streams[key]);
			}
		}

		public static string ReadTextResource(string assembly, string path, System.Text.Encoding encoding)
		{
			return AssemblyStreamManager.ReadTextFromResource(assembly, path, encoding);
		}

		public static string ReadTextResource(string path, System.Text.Encoding encoding)
		{
			return AssemblyStreamManager.ReadTextFromResource(null, path, encoding);
		}

		public static string ReadTextResource(string assembly, string path)
		{
			return AssemblyStreamManager.ReadTextFromResource(assembly, path, System.Text.Encoding.Unicode);
		}

		public static string ReadTextResource(string path)
		{
			return AssemblyStreamManager.ReadTextFromResource(null, path, System.Text.Encoding.Unicode);
		}
	}
}